package cn.chiship.sdk.pay.core.util;

import cn.chiship.sdk.core.base.BaseResult;
import cn.chiship.sdk.core.util.StringUtil;
import cn.chiship.sdk.pay.core.config.WxPayV3Config;
import cn.chiship.sdk.pay.core.model.PayBillDownloadModel;
import cn.chiship.sdk.pay.core.model.wx.WxPrepay;
import cn.chiship.sdk.pay.core.model.wx.WxRefund;
import cn.chiship.sdk.pay.core.model.wx.WxTransfer;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.util.NonceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Instant;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 微信支付v3工具
 *
 * @author lj
 */
public class WxPayV3Util {

    protected static final Logger LOGGER = LoggerFactory.getLogger(WxPayV3Util.class);

    /**
     * v3 jsapi下单
     */
    public final static String PAY_V3_JSAPI = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";

    /**
     * v3 native下单
     */
    public final static String PAY_V3_NATIVE = "https://api.mch.weixin.qq.com/v3/pay/transactions/native";

    /**
     * v3 h5下单
     */
    public final static String PAY_V3_H5 = "https://api.mch.weixin.qq.com/v3/pay/transactions/h5";

    /**
     * v3 查询订单
     */
    public final static String PAY_V3_QUERY_ORDER1 = "https://api.mch.weixin.qq.com/v3/pay/transactions/id/%s?mchid=%s";

    public final static String PAY_V3_QUERY_ORDER2 = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s?mchid=%s";

    /**
     * v3 申请退款
     */
    public final static String PAY_V3_REFUND = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";

    /**
     * v3 查询单笔退款
     */
    public final static String PAY_V3_QUERY_REFUND = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/%s";

    /**
     * v3 批次转账
     */
    public final static String PAY_V3_TRANSFER_BATCH = "https://api.mch.weixin.qq.com/v3/transfer/batches";

    /**
     * v3 转账查询
     */
    public final static String PAY_V3_TRANSFER_QUERY = "https://api.mch.weixin.qq.com/v3/transfer/batches/out-batch-no/%s/details/out-detail-no/%s";

    private static WxPayV3Util wxPayV3Util;

    private WxPayV3Config wxPayV3Config;

    private WxPayV3HttpUtil wxPayV3HttpUtil;

    private final static Map<String, Config> wxConfigMap = new ConcurrentHashMap<>();

    /**
     * 预留支付句柄
     */
    private Config config;

    private WxPayV3Util() {
    }

    public static synchronized WxPayV3Util getInstance() {
        if (wxPayV3Util == null) {
            wxPayV3Util = new WxPayV3Util();
        }

        return wxPayV3Util;
    }

    public WxPayV3Util config(WxPayV3Config wxPayV3Config) {
        this.wxPayV3Config = wxPayV3Config;
        this.wxPayV3HttpUtil = createWxHttp();
        this.config = createWxConfig();

        return this;
    }

    /**
     * 扫码支付
     *
     * @param wxPrepay
     * @return 结果
     */
    public BaseResult doQrCodePay(WxPrepay wxPrepay) {
        LOGGER.info("-----------------进入微信v3扫码支付-----------------------");
        JSONObject bodyJSON = JSON.parseObject(JSON.toJSONString(wxPrepay));
        BaseResult baseResult = wxPayV3HttpUtil.sendPost(PAY_V3_NATIVE, bodyJSON);
        if (!baseResult.isSuccess()) {
            return baseResult;
        }
        JSONObject json = (JSONObject) baseResult.getData();
        return BaseResult.ok(json.getString("code_url"));

    }

    /**
     * 微信H5支付
     *
     * @param wxPrepay
     * @return 结果
     */
    public BaseResult doH5Pay(WxPrepay wxPrepay) {
        LOGGER.info("-----------------进入微信v3 H5支付-----------------------");
        return BaseResult.error("待接入");

    }

    /**
     * 微信JSAPI支付
     *
     * @param wxPrepay
     * @return 结果
     */
    public BaseResult doJsApiPay(WxPrepay wxPrepay) {
        LOGGER.info("-----------------进入微信v3 JSAPI支付-----------------------");
        JSONObject bodyJSON = JSON.parseObject(JSON.toJSONString(wxPrepay));
        BaseResult baseResult = wxPayV3HttpUtil.sendPost(PAY_V3_JSAPI, bodyJSON);
        if (!baseResult.isSuccess()) {
            return baseResult;
        }
        JSONObject prepayJSON = (JSONObject) baseResult.getData();
        String prepayId = prepayJSON.getString("prepay_id");
        long timestamp = Instant.now().getEpochSecond();
        String nonceStr = NonceUtil.createNonce(32);
        String packageVal = "prepay_id=" + prepayId;
        String message = wxPayV3Config.getAppId() + "\n" + timestamp + "\n" + nonceStr + "\n" + packageVal + "\n";
        baseResult = wxPayV3HttpUtil.signRSA(message);
        if (!baseResult.isSuccess()) {
            return baseResult;
        }
        JSONObject responseJSON = new JSONObject();
        responseJSON.put("appId", wxPayV3Config.getAppId());
        responseJSON.put("timeStamp", String.valueOf(timestamp));
        responseJSON.put("signType", "RSA");
        responseJSON.put("paySign", StringUtil.getString(baseResult.getData()));
        responseJSON.put("packageVal", packageVal);
        responseJSON.put("nonceStr", nonceStr);
        responseJSON.put("orderId", wxPrepay.getOutTradeNo());
        return BaseResult.ok(responseJSON);
    }

    /**
     * 订单查询
     *
     * @param transactionId 交易号
     * @param isOrder       true 订单号查询 false 流水号查询
     * @return BaseResult
     */
    public BaseResult doOrderQuery(String transactionId, Boolean isOrder) {
        LOGGER.info("-----------------进入微信v3 订单查询-----------------------");
        if (isOrder) {
            return wxPayV3HttpUtil.sendGet(String.format(PAY_V3_QUERY_ORDER2, transactionId, wxPayV3Config.getMchId()));
        } else {
            return wxPayV3HttpUtil.sendGet(String.format(PAY_V3_QUERY_ORDER1, transactionId, wxPayV3Config.getMchId()));
        }

    }

    /**
     * 下载账单
     *
     * @param payBillDownloadModel 账单下载实体
     * @return BaseResult
     */
    public BaseResult downloadBill(PayBillDownloadModel payBillDownloadModel) {
        try {
            return BaseResult.error("暂未实现");
        } catch (Exception e) {
            return BaseResult.error(e.getLocalizedMessage());

        }
    }

    /**
     * 退款
     *
     * @param wxRefund
     * @return BaseResult
     */
    public BaseResult doRefund(WxRefund wxRefund) {
        LOGGER.info("-----------------进入微信v3 退款-----------------------");
        JSONObject bodyJSON = JSON.parseObject(JSON.toJSONString(wxRefund));
        return wxPayV3HttpUtil.sendPost(PAY_V3_REFUND, bodyJSON);
    }

    /**
     * 退款查询
     *
     * @param refundId 商户退款单号
     * @return BaseResult
     */
    public BaseResult doRefundQuery(String refundId) {
        LOGGER.info("-----------------进入微信v3 退款查询-----------------------");

        return wxPayV3HttpUtil.sendGet(String.format(PAY_V3_QUERY_REFUND, refundId));
    }

    /**
     * 批次转账
     *
     * @param wxTransfer
     * @return BaseResult
     */
    public BaseResult doTransferBatch(WxTransfer wxTransfer) {
        LOGGER.info("-----------------进入微信v3 转账-----------------------");
        JSONObject bodyJSON = JSON.parseObject(JSON.toJSONString(wxTransfer));
        return wxPayV3HttpUtil.sendPost(PAY_V3_TRANSFER_BATCH, bodyJSON);
    }

    /**
     * 转账查询
     *
     * @param transferNo
     * @return BaseResult
     */
    public BaseResult doTransferQuery(String transferNo) {
        LOGGER.info("-----------------进入微信v3 转账查询-----------------------");
        return wxPayV3HttpUtil.sendGet(String.format(PAY_V3_TRANSFER_QUERY, transferNo, transferNo));
    }

    /**
     * 创建支付句柄
     *
     * @return WXPay
     */
    private Config createWxConfig() {

        Config config = wxConfigMap.get(wxPayV3Config.getMchId());
        if (config == null) {
            config = new RSAAutoCertificateConfig.Builder().merchantId(wxPayV3Config.getMchId())
                    .privateKey(wxPayV3Config.getPrivateKey()).merchantSerialNumber(wxPayV3Config.getSerialNumber())
                    .apiV3Key(wxPayV3Config.getMchKey()).build();
            wxConfigMap.put(wxPayV3Config.getMchId(), config);
        }

        return config;
    }

    /**
     * 创建微信网络请求句柄
     *
     * @return
     */
    private WxPayV3HttpUtil createWxHttp() {
        return WxPayV3HttpUtil.getInstance().config(wxPayV3Config);
    }

}
